package org.ovirt.microvirt.utils;

import java.util.Collections;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.provider.ProviderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VerboseExceptionMapper<E extends Throwable> implements
		ExceptionMapper<E> {

	private final static Logger logger = LoggerFactory
			.getLogger(VerboseExceptionMapper.class);

	@XmlRootElement(name="error")
	public final static class Error {
		String message;
		String code;
		String type;
		@XmlValue
		public String getMessage() {
			return message;
		}
		public void setMessage(String message) {
			this.message = message;
		}
		@XmlAttribute(name="code")
		public String getCode() {
			return code;
		}
		public void setCode(String code) {
			this.code = code;
		}
		@XmlAttribute(name="type")
		public String getType() {
			return type;
		}
		public void setType(String type) {
			this.type = type;
		}
	}
	
	public void register() {
		ProviderFactory.getSharedInstance().setUserProviders(Collections.singletonList(this));
	}

	@Override
	public Response toResponse(final E exception) {

		logger.error(exception.getMessage(), exception);
		return new Response() {

			@Override
			public Object getEntity() {
				final Error error = new Error();
				error.setMessage(exception.getMessage());
				error.setType(exception.getClass().getName());
				return error;
			}

			@Override
			public int getStatus() {
				return 500;
			}

			@Override
			public MultivaluedMap<String, Object> getMetadata() {
				final MetadataMap<String, Object> metadataMap = new MetadataMap<String, Object>();
				metadataMap.add("error", exception.getMessage());
				return metadataMap;
			}
		};
	}

}
